home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / utility3 / wincap.zip / PRINT.C < prev    next >
C/C++ Source or Header  |  1991-11-05  |  25KB  |  701 lines

  1. /*
  2.  *  print.c
  3.  *
  4.  *  Source file for Device-Independent Bitmap (DIB) API.  Provides
  5.  *  the following functions:
  6.  *
  7.  *  PrintWindow()       - Prints all or part of a window
  8.  *  PrintScreen()       - Prints the entire screen
  9.  *  PrintDIB()          - Prints the specified DIB
  10.  *
  11.  * Development Team: Mark Bader
  12.  *                   Patrick Schreiber
  13.  *                   Garrett McAuliffe
  14.  *                   Eric Flo
  15.  *                   Tony Claflin
  16.  *
  17.  * Written by Microsoft Product Support Services, Developer Support.
  18.  * Copyright (c) 1991 Microsoft Corporation. All rights reserved.
  19.  */
  20. #include <windows.h>
  21. #include <string.h>
  22. #include "dibapi.h"     // Header for DIB functions
  23. #include "dibutil.h"    // Auxilirary functions
  24. #include "dialogs.h"    // Header for "Now Printing" dialog box
  25. #include "errors.h"     // Contains error numbers
  26.  
  27. extern HANDLE ghInst;     // Global handle to instance of main window
  28.  
  29. /***************************************************************
  30.  * Typedefs
  31.  **************************************************************/
  32.  
  33. /* Structure used for Banding */
  34.  
  35. typedef struct
  36. {
  37.    BOOL bGraphics;
  38.    BOOL bText;
  39.    RECT GraphicsRect;
  40. } BANDINFOSTRUCT;
  41.  
  42.  
  43. /****************************************************************
  44.  * Variables
  45.  ***************************************************************/
  46.  
  47. HWND hDlgAbort;                    // Handle to Abort Dialog
  48. char szPrintDlg[] = "Printing";    // Name of Print dialog from .RC
  49. BOOL bAbort = FALSE;               // Abort a print operation?
  50. char gszDevice[50];                // Keeps track out device (e.g. "HP LaserJet")
  51. char gszOutput[50];                // Output device (e.g. "LPT1:")
  52.  
  53. /***************************************************************
  54.  * Function prototypes for functions local to this module
  55.  **************************************************************/
  56.  
  57.  
  58. BOOL FAR PASCAL PrintAbortProc(HDC, short);
  59. int FAR PASCAL PrintAbortDlg(HWND, unsigned, WORD, LONG);
  60. WORD PrintBand(HDC, LPRECT, LPRECT, BOOL, BOOL, LPBITMAPINFOHEADER, LPSTR);
  61. HDC GetPrinterDC(void);
  62. void CalculatePrintRect(HDC, LPRECT, WORD, DWORD, DWORD);
  63.  
  64.  
  65. /**********************************************************************
  66.  *
  67.  * PrintWindow()
  68.  *
  69.  *
  70.  * Description:
  71.  *
  72.  * This function prints the specified window on the default
  73.  * printer.
  74.  *
  75.  * Parameters:
  76.  *
  77.  * HWND hWnd       - Specifies the window to print.  The window must
  78.  *                   not be iconic and must be topmost on the display.
  79.  *
  80.  * WORD fPrintArea - Specifies the area of the window to print.  Must be
  81.  *                   one of PW_ALL, PW_CLIENT, PW_CAPTION,  or PW_MENUBAR
  82.  *
  83.  * WORD fPrintOpt  - Print options (one of PW_BESTFIT, PW_STRETCHTOPAGE, or
  84.  *                   PW_SCALE)
  85.  *
  86.  * WORD wXScale, wYScale - X and Y scaling factors if PW_SCALE is specified
  87.  *
  88.  * LPSTR szJobName - Name that you would like to give to this print job (this
  89.  *                   name shows up in the Print Manager as well as the
  90.  *                   "Now Printing..." dialog box).
  91.  * Return Value:
  92.  *      ERR_DIBFUNCTION or any return value from PrintDIB
  93.  *
  94.  **********************************************************************/
  95.  
  96.  
  97. WORD PrintWindow(HWND hWnd,         // Window to be printed
  98.                  WORD fPrintArea,   // Area of window to be printed
  99.                  WORD fPrintOpt,    // Print options
  100.                  WORD wXScale,      // X Scaling factor if PW_SCALE is used
  101.                  WORD wYScale,      // Y Scaling factor if PW_SCALE is used
  102.                  LPSTR szJobName)   // Name of print job
  103. {
  104.    HDIB hDib;          // Handle to the DIB
  105.    WORD wReturn;       // our return value
  106.  
  107.    /*
  108.     * Parameter validation
  109.     */
  110.    if (!hWnd)
  111.       return (ERR_INVALIDHANDLE);  // Invalid Window
  112.  
  113.    /*
  114.     * Copy the Window to a DIB and print it.
  115.     */
  116.    hDib = CopyWindowToDIB(hWnd, fPrintArea);
  117.    if (!hDib)
  118.       return (ERR_DIBFUNCTION); // CopyWindowToDIB failed!
  119.    wReturn = PrintDIB(hDib, fPrintOpt, wXScale, wYScale, szJobName);
  120.  
  121.    /*
  122.     * Call DestroyDIB to free the memory the dib takes up.
  123.     */
  124.    DestroyDIB(hDib);
  125.    return wReturn;   // return the value from PrintDIB
  126. }
  127.  
  128.  
  129.  
  130. /**********************************************************************
  131.  *
  132.  * PrintScreen()
  133.  *
  134.  *
  135.  * Description:
  136.  *
  137.  * This function prints the specified portion of the display screen on the
  138.  * default printer using the print options specified.  The print
  139.  * options are listed in dibapi.h.
  140.  *
  141.  * Parameters:
  142.  *
  143.  * LPRECT rRegion  - Specifies the region of the screen (in screen
  144.  *                   coordinates) to print
  145.  *
  146.  * WORD fPrintOpt  - Print options  (PW_BESTFIT, PW_STRETCHTOPAGE, or PW_SCALE)
  147.  *
  148.  * WORD wXScale, wYScale - X and Y scaling factors if PW_SCALE is specified
  149.  *
  150.  * LPSTR szJobName - Name that you would like to give to this print job (this
  151.  *                   name shows up in the Print Manager as well as the
  152.  *                   "Now Printing..." dialog box).
  153.  *
  154.  * Return Value:
  155.  *      ERR_DIBFUNCTION or any return value from PrintDIB
  156.  *
  157.  **********************************************************************/
  158.  
  159.  
  160. WORD PrintScreen(LPRECT rRegion,    // Region to print (in screen coords)
  161.                  WORD fPrintOpt,    // print options
  162.                  WORD wXScale,      // X scaling (used if PW_SCALE specified)
  163.                  WORD wYScale,      // Y scaling (used if PW_SCALE specified)
  164.                  LPSTR szJobName)   // Name of print job
  165. {
  166.    HDIB hDib;          // A Handle to our DIB
  167.    WORD wReturn;       // Return value
  168.  
  169.    /*
  170.     * Copy the screen contained in the specified rectangle to a DIB
  171.     */
  172.    hDib = CopyScreenToDIB(rRegion);
  173.    if (!hDib)
  174.       return (ERR_DIBFUNCTION);   // CopyScreenToDIB failed!
  175.    wReturn = PrintDIB(hDib, fPrintOpt, wXScale, wYScale, szJobName);
  176.    DestroyDIB(hDib);
  177.    return wReturn; // Return the value that PrintDIB returned
  178. }
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185. /**********************************************************************
  186.  *
  187.  * PrintDIB()
  188.  *
  189.  * Description:
  190.  *
  191.  * This routine prints the specified DIB.  The actual printing is done
  192.  * in the PrintBand() routine (see below), this procedure drives the
  193.  * printing operation.  PrintDIB() has the code to handle both banding
  194.  * and non-banding printers.  A banding printer can be distinguished by
  195.  * the GetDeviceCaps() API (see the code below).  On banding devices,
  196.  * must repeatedly call the NEXTBAND escape to get the next banding
  197.  * rectangle to print into.  If the device supports the BANDINFO escape,
  198.  * it should be used to determine whether the band "wants" text or
  199.  * graphics (or both).  On non-banding devices, we can ignore all this
  200.  * and call PrintBand() on the entire page.
  201.  *
  202.  * Parameters:
  203.  *
  204.  * HDIB hDib       - Handle to dib to be printed
  205.  *
  206.  * WORD fPrintOpt  - tells which print option to use (PW_BESTFIT,
  207.  *                   PW_STRETCHTOPAGE, OR PW_SCALE)
  208.  *
  209.  * WORD wXScale, wYScale - X and Y scaling factors (integers) for
  210.  *                   printed output if the PW_SCALE option is used.
  211.  *
  212.  * LPSTR szJobName - Name that you would like to give to this print job (this
  213.  *                   name shows up in the Print Manager as well as the
  214.  *                   "Now Printing..." dialog box).
  215.  *
  216.  * Return Value:  (see errors.h for description)
  217.  *
  218.  * One of: ERR_INVALIDHANDLE
  219.  *         ERR_LOCK
  220.  *         ERR_SETABORTPROC
  221.  *         ERR_STARTDOC
  222.  *         ERR_NEWFRAME
  223.  *         ERR_ENDDOC
  224.  *         ERR_GETDC
  225.  *         ERR_STRETCHDIBITS
  226.  *
  227.  *
  228.  ********************************************************************/
  229.  
  230.  
  231. WORD PrintDIB(HDIB hDib,        // Handle to the DIB
  232.               WORD fPrintOpt,   // Print Options
  233.               WORD wXScale,     // X Scaling factor
  234.               WORD wYScale,     // Y Scaling factor
  235.               LPSTR szJobName)  // Name of print job
  236. {
  237.    HDC hPrnDC;                  // DC to the printer
  238.    RECT rect;                   // Rect structure used for banding
  239.    BANDINFOSTRUCT biBandInfo;   // Used for banding
  240.    static FARPROC lpAbortProc;  // ProcInstance to the Abort Proc
  241.    static FARPROC lpAbortDlg;   // ProcInstance to the Dialog Box Procedure
  242.    int nTemp;                   // Temp number used to check banding capability
  243.    LPSTR lpBits;                // pointer to the DIB bits
  244.    LPBITMAPINFOHEADER lpDIBHdr; // Pointer to DIB header
  245.    int nBandCount = 0;          // used for print dialog box to count bands
  246.    WORD wErrorCode = 0;         // Error code to return
  247.    RECT rPrintRect;             // Rect which specifies the area on the printer
  248.                                 // (in printer coordinates) which we
  249.                                 // want the DIB to go to
  250.    char szBuffer[70];           // Buffer to hold message for "Printing" dlg box
  251.    char szJobNameTrunc[35];     // szJobName truncated to 31 characters, since
  252.                                 // STARTDOC can't accept a string longer than 31
  253.  
  254.    /*
  255.     * Paramter validation
  256.     */
  257.    if (!hDib)
  258.       return (ERR_INVALIDHANDLE);
  259.  
  260.    /*
  261.     * Get pointer to DIB header
  262.     */
  263.    lpDIBHdr = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  264.    if (!lpDIBHdr) // Check that we have a valid pointer
  265.       return (ERR_LOCK);
  266.    lpBits = FindDIBBits((LPSTR)lpDIBHdr); // Find pointer to DIB bits
  267.    if (hPrnDC = GetPrinterDC())
  268.    {
  269.       SetStretchBltMode(hPrnDC, COLORONCOLOR);
  270.  
  271.       /*
  272.        * Determine rPrintRect (printer area to print to) from the
  273.        * fPrintOpt.  Fill in rPrintRect.left and .top from wXScale and
  274.        * wYScale just in case we use PW_SCALE (see the function
  275.        * CalculatePrintRect).
  276.        */
  277.       rPrintRect.left = wXScale;
  278.       rPrintRect.top = wYScale;
  279.       CalculatePrintRect(hPrnDC, &rPrintRect, fPrintOpt, lpDIBHdr->biWidth,
  280.                          lpDIBHdr->biHeight);
  281.  
  282.       /*
  283.        * Initialize the abort procedure.
  284.        */
  285.       lpAbortProc = MakeProcInstance(PrintAbortProc, ghInst);
  286.       lpAbortDlg = MakeProcInstance(PrintAbortDlg, ghInst);
  287.       hDlgAbort = CreateDialog(ghInst, szPrintDlg, GetFocus(), lpAbortDlg);
  288.  
  289.       /*
  290.        * Set the text inside the dialog to the name of our print job
  291.        */
  292.       lstrcpy(szJobNameTrunc, szJobName);
  293.       szJobNameTrunc[31] = '\0';           // Truncate string to 31 chars
  294.       wsprintf(szBuffer, "Printing '%s'", (LPSTR)szJobNameTrunc);
  295.       SetDlgItemText(hDlgAbort, IDC_PRINTTEXT1, (LPSTR)szBuffer);
  296.  
  297.       /*
  298.        * Set global variable bAbort to FALSE.  This will get set to TRUE
  299.        * in our PrintAbortDlg() proceudre if the user selects the
  300.        * CANCEL button in our dialog box
  301.        */
  302.       bAbort = FALSE;
  303.  
  304.       /*
  305.        * Call the Escape() which will set up the Abort Procedure
  306.        */
  307.       if (Escape(hPrnDC, SETABORTPROC, NULL, (LPSTR)(FARPROC)lpAbortProc, NULL
  308.                  ) < 0)
  309.          return (ERR_SETABORTPROC);
  310.  
  311.       /*
  312.        * Call Escape() with STARTDOC -- starts print job
  313.        */
  314.       if (Escape(hPrnDC, STARTDOC, lstrlen((LPSTR)szJobNameTrunc), (LPSTR)
  315.                  szJobNameTrunc, NULL) < 0)
  316.       {
  317.  
  318.          // Oops, something happened, let's clean up here and return
  319.          DestroyWindow(hDlgAbort);   // Remove abort dialog box
  320.          FreeProcInstance(lpAbortProc);
  321.          FreeProcInstance(lpAbortDlg);
  322.          DeleteDC(hPrnDC);
  323.          GlobalUnlock(hDib);
  324.          return (ERR_STARTDOC);
  325.       }
  326.  
  327.       /*
  328.        * Fill in initial values for our BandInfo Structure to
  329.        * tell driver we can want to do graphics and text, and
  330.        * also which area we want the graphics to go in.
  331.        */
  332.       biBandInfo.bGraphics = TRUE;
  333.       biBandInfo.bText = TRUE;
  334.       biBandInfo.GraphicsRect = rPrintRect;
  335.  
  336.       /*
  337.        * Check if need to do banding.  If we do, loop through
  338.        *  each band in the page, calling NEXTBAND and BANDINFO
  339.        *  (if supported) calling PrintBand() on the band.  Else,
  340.        *  call PrintBand() with the entire page as our clipping
  341.        *  rectangle!
  342.        */
  343.       nTemp = NEXTBAND;
  344.       if (Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR)&nTemp, NULL))
  345.       {
  346.          BOOL bBandInfoDevice;
  347.  
  348.          /*
  349.           * Check if device supports the BANDINFO escape.
  350.           */
  351.  
  352.          nTemp = BANDINFO;
  353.          bBandInfoDevice = Escape(hPrnDC, QUERYESCSUPPORT, sizeof(int), (LPSTR
  354.                                   )&nTemp, NULL);
  355.  
  356.          /*
  357.           * Do each band -- Call Escape() with NEXTBAND, then the
  358.           * rect structure returned is the area where we are to
  359.           * print in.  This loop exits when the rect area is empty.
  360.           */
  361.          while (Escape(hPrnDC, NEXTBAND, NULL, NULL, (LPSTR)&rect) && !
  362.                 IsRectEmpty(&rect))
  363.          {
  364.             char szTmpBuf[100];
  365.  
  366.             /*
  367.              * Do the BANDINFO, if needed.
  368.              */
  369.  
  370.             if (bBandInfoDevice)
  371.                Escape(hPrnDC, BANDINFO, sizeof(BANDINFOSTRUCT), (LPSTR)&
  372.                       biBandInfo, (LPSTR)&biBandInfo);
  373.             wsprintf(szTmpBuf, "Printing Band Number %d", ++nBandCount);
  374.             SetDlgItemText(hDlgAbort, IDC_PERCENTAGE, (LPSTR)szTmpBuf);
  375.  
  376.             /*
  377.              * Call PrintBand() to do actual output into band.
  378.              *  Pass in our band-info flags to tell what sort
  379.              *  of data to output into the band.  Note that on
  380.              *  non-banding devices, we pass in the default bandinfo
  381.              *  stuff set above (i.e. bText=TRUE, bGraphics=TRUE).
  382.              */
  383.             wErrorCode = PrintBand(hPrnDC, &rPrintRect, &rect,
  384.                                    biBandInfo.bText, biBandInfo.bGraphics,
  385.                                    lpDIBHdr, lpBits);
  386.          }
  387.       }
  388.       else
  389.       {
  390.  
  391.          /*
  392.           * Print the whole page -- non-banding device.
  393.           */
  394.          rect = rPrintRect;
  395.          SetDlgItemText(hDlgAbort, IDC_PERCENTAGE, (LPSTR)
  396.                         "Sending bitmap to printer...");
  397.          wErrorCode = PrintBand(hPrnDC, &rPrintRect, &rect, TRUE, TRUE,
  398.                                 lpDIBHdr, lpBits);
  399.  
  400.          /*
  401.           * Non-banding devices need a NEWFRAME
  402.           */
  403.          if (Escape(hPrnDC, NEWFRAME, NULL, NULL, NULL) < 0)
  404.             return (ERR_NEWFRAME);
  405.       }
  406.  
  407.       /*
  408.        * End the print operation.  Only send the ENDDOC if
  409.        *   we didn't abort or error.
  410.        */
  411.       if (!bAbort)
  412.       {
  413.          if (Escape(hPrnDC, ENDDOC, NULL, NULL, NULL) < 0)
  414.          {
  415.             /*
  416.              * We errored out on ENDDOC, but don't return here - we still
  417.              * need to close the dialog box, free proc instances, etc.
  418.              */
  419.             wErrorCode = ERR_ENDDOC;
  420.          }
  421.          DestroyWindow(hDlgAbort);
  422.       }
  423.  
  424.  
  425.       /*
  426.        * All done, clean up.
  427.        */
  428.       FreeProcInstance(lpAbortProc);
  429.       FreeProcInstance(lpAbortDlg);
  430.       DeleteDC(hPrnDC);
  431.    }
  432.    else
  433.       wErrorCode = ERR_GETDC;   // Couldn't get Printer DC!
  434.    GlobalUnlock(hDib);
  435.    return (wErrorCode);
  436. }
  437.  
  438.  
  439.  
  440.  
  441. // *******************************************************************
  442. // Auxilirary Functions
  443. //     -- Local to this module only
  444. // *******************************************************************
  445.  
  446.  
  447. /*********************************************************************
  448.  *
  449.  * CalculatePrintRect()
  450.  *
  451.  * Given fPrintOpt and a size of the DIB, return the area on the
  452.  * printer where the image should go (in printer coordinates).  If
  453.  * fPrintOpt is PW_SCALE, then lpPrintRect.left and .top should
  454.  * contain WORDs which specify the scaling factor for the X and
  455.  * Y directions, respecively.
  456.  *
  457.  ********************************************************************/
  458.  
  459.  
  460. void CalculatePrintRect(HDC hDC,             // HDC to printer DC
  461.                         LPRECT lpPrintRect,  // Returned PrintRect
  462.                         WORD fPrintOpt,      // Options
  463.                         DWORD cxDIB,         // Size of DIB - x
  464.                         DWORD cyDIB)         // Size of DIB - y
  465. {
  466.    int cxPage, cyPage, cxInch, cyInch;
  467.  
  468.    if (!hDC)
  469.       return;
  470.  
  471.    /*
  472.     * Get some info from printer driver
  473.     */
  474.    cxPage = GetDeviceCaps(hDC, HORZRES);     // Width of printr page - pixels
  475.    cyPage = GetDeviceCaps(hDC, VERTRES);     // Height of printr page - pixels
  476.    cxInch = GetDeviceCaps(hDC, LOGPIXELSX);  // Printer pixels per inch - X
  477.    cyInch = GetDeviceCaps(hDC, LOGPIXELSY);  // Printer pixels per inch - Y
  478.    switch (fPrintOpt)
  479.       {
  480.  
  481.    /*
  482.     * Best Fit case -- create a rectangle which preserves
  483.     * the DIB's aspect ratio, and fills the page horizontally.
  484.     *
  485.     * The formula in the "->bottom" field below calculates the Y
  486.     * position of the printed bitmap, based on the size of the
  487.     * bitmap, the width of the page, and the relative size of
  488.     * a printed pixel (cyInch / cxInch).
  489.     */
  490.    case PW_BESTFIT:
  491.       lpPrintRect->top = 0;
  492.       lpPrintRect->left = 0;
  493.       lpPrintRect->bottom = (int)(((double)cyDIB * cxPage * cyInch) / ((double
  494.                             )cxDIB * cxInch));
  495.       lpPrintRect->right = cxPage;
  496.       break;
  497.  
  498.    /*
  499.     * Scaling option -- lpPrintRect's top/left contain
  500.     * multipliers to multiply the DIB's height/width by.
  501.     */
  502.  
  503.    case PW_SCALE:
  504.    {
  505.       int cxMult, cyMult;
  506.  
  507.       cxMult = lpPrintRect->left;
  508.       cyMult = lpPrintRect->top;
  509.       lpPrintRect->top = 0;
  510.       lpPrintRect->left = 0;
  511.       lpPrintRect->bottom = (int)(cyDIB * cyMult);
  512.       lpPrintRect->right = (int)(cxDIB * cxMult);
  513.    }
  514.       break;
  515.  
  516.    /*
  517.     * Stretch To Page case -- create a rectangle
  518.     * which covers the entire printing page (note that this
  519.     * is also the default).
  520.     */
  521.    case PW_STRETCHTOPAGE:
  522.    default:
  523.       lpPrintRect->top = 0;
  524.       lpPrintRect->left = 0;
  525.       lpPrintRect->bottom = cyPage;
  526.       lpPrintRect->right = cxPage;
  527.       break;
  528.       }
  529. }
  530.  
  531.  
  532.  
  533. /*********************************************************************
  534.  *
  535.  * PrintBand()
  536.  *
  537.  * This routine does ALL output to the printer.  It is called from
  538.  * the PrintDIB() routine.  It is called for both banding and non-
  539.  * banding printing devices.  lpRectClip contains the rectangular
  540.  * area we should do our output into (i.e. we should clip our output
  541.  * to this area).  The flags fDoText and fDoGraphics should be set
  542.  * appropriately (if we want any text output to the rectangle, set
  543.  * fDoText to true).  Normally these flags are returned on banding
  544.  * devices which support the BANDINFO escape.
  545.  *
  546.  ********************************************************************/
  547.  
  548.  
  549. WORD PrintBand(HDC hDC,           // Handle to the Printer DC
  550.                LPRECT lpRectOut,  // Rect where entire DIB is to go
  551.                LPRECT lpRectClip, // Clippping rect where this portion goes
  552.                BOOL fDoText,      // TRUE if this band is for text
  553.                BOOL fDoGraphics,  // TRUE if this band is for graphics
  554.                LPBITMAPINFOHEADER lpDIBHdr,   // Pointer to DIB header
  555.                LPSTR lpDIBBits)   // Pointer to DIB bits
  556. {
  557.    RECT rect;                   // Temporary rectangle
  558.    double dblXScaling,          // X and Y scaling factors
  559.           dblYScaling;
  560.    WORD wReturn = 0;            // Return code
  561.  
  562.    if (fDoGraphics)
  563.    {
  564.       dblXScaling = ((double)lpRectOut->right - lpRectOut->left) / (double)
  565.                     lpDIBHdr->biWidth;
  566.       dblYScaling = ((double)lpRectOut->bottom - lpRectOut->top) / (double)
  567.                     lpDIBHdr->biHeight;
  568.       /*
  569.        * Now we set up a temporary rectangle -- this rectangle
  570.        *  holds the coordinates on the paper where our bitmap
  571.        *  WILL be output.  We can intersect this rectangle with
  572.        *  the lpClipRect to see what we NEED to output to this
  573.        *  band.  Then, we determine the coordinates in the DIB
  574.        *  to which this rectangle corresponds (using dbl?Scaling).
  575.        */
  576.       IntersectRect(&rect, lpRectOut, lpRectClip);
  577.       if (!IsRectEmpty(&rect))
  578.       {
  579.          RECT rectIn;
  580.  
  581.          rectIn.left = (int)((rect.left - lpRectOut->left) / dblXScaling + 0.5
  582.                        );
  583.          rectIn.top = (int)((rect.top - lpRectOut->top) / dblYScaling + 0.5);
  584.          rectIn.right = (int)(rectIn.left + (rect.right - rect.left) /
  585.                         dblXScaling + 0.5);
  586.          rectIn.bottom = (int)(rectIn.top + (rect.bottom - rect.top) /
  587.                          dblYScaling + 0.5);
  588.          if (!StretchDIBits(hDC,                              // DestDC
  589.                             rect.left,                        // DestX
  590.                             rect.top,                         // DestY
  591.                             rect.right - rect.left,           // DestWidth
  592.                             rect.bottom - rect.top,           // DestHeight
  593.                             rectIn.left,                      // SrcX
  594.                             (int)(lpDIBHdr->biHeight) -       // SrcY
  595.                             rectIn.top - (rectIn.bottom - rectIn.top),
  596.                             rectIn.right - rectIn.left,       // SrcWidth
  597.                             rectIn.bottom - rectIn.top,       // SrcHeight
  598.                             lpDIBBits,                        // lpBits
  599.                             (LPBITMAPINFO)lpDIBHdr,           // lpBitInfo
  600.                             DIB_RGB_COLORS,                   // wUsage
  601.                             SRCCOPY))                         // dwROP
  602.             wReturn = ERR_STRETCHDIBITS; // StretchDIBits() failed!
  603.       }
  604.    }
  605.    return wReturn;
  606. }
  607.  
  608.  
  609. /***********************************************************************
  610.  *
  611.  * GetPrinterDC()
  612.  *
  613.  * Return a DC to the currently selected printer.
  614.  * Returns NULL on error.
  615.  *
  616.  ***********************************************************************/
  617.  
  618.  
  619. HDC GetPrinterDC(void)
  620. {
  621.    static char szPrinter[64];
  622.    char *szDevice, *szDriver, *szOutput;
  623.  
  624.    GetProfileString("windows", "device", "", szPrinter, 64);
  625.    if ((szDevice = strtok(szPrinter, ",")) && (szDriver = strtok(NULL, ", "))
  626.        && (szOutput = strtok(NULL, ", ")))
  627.    {
  628.       lstrcpy((LPSTR)gszDevice, (LPSTR)szDevice);    // Copy to global variables
  629.       lstrcpy((LPSTR)gszOutput, (LPSTR)szOutput);
  630.       return CreateDC(szDriver, szDevice, szOutput, NULL);
  631.    }
  632.    return NULL;
  633. }
  634.  
  635.  
  636. /**********************************************************************
  637.  * PrintAbortProc()
  638.  *
  639.  * Abort procedure - contains the message loop while printing is
  640.  * in progress.  By using a PeekMessage() loop, multitasking
  641.  * can occur during printing.
  642.  *
  643.  **********************************************************************/
  644.  
  645.  
  646. BOOL FAR PASCAL PrintAbortProc(HDC hDC, short code)
  647. {
  648.    MSG msg;
  649.  
  650.    while (!bAbort && PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  651.       if (!IsDialogMessage(hDlgAbort, &msg))
  652.       {
  653.          TranslateMessage(&msg);
  654.          DispatchMessage(&msg);
  655.       }
  656.    return (!bAbort);
  657. }
  658.  
  659. /***********************************************************************
  660.  *
  661.  * PrintAbortDlg()
  662.  *
  663.  *
  664.  * This is the Dialog Procedure which will handle the "Now Printing"
  665.  * dialog box.  When the user presses the "Cancel" button, the
  666.  * global variable bAbort is set to TRUE, which causes the
  667.  * PrintAbortProc to exit, which in turn causes the printing
  668.  * operation to terminate.
  669.  *
  670.  ***********************************************************************/
  671.  
  672.  
  673. int FAR PASCAL PrintAbortDlg(HWND hWnd,   /* Handle to dialog box */ unsigned
  674.                              msg, /* Message */ WORD wParam, LONG lParam)
  675. {
  676.    switch (msg)
  677.       {
  678.    case WM_INITDIALOG:
  679.    {
  680.       char szBuffer[100];
  681.  
  682.       /*
  683.        * Fill in the text which specifies where this bitmap
  684.        * is going ("on HP LaserJet on LPT1", for example)
  685.        */
  686.  
  687.       wsprintf(szBuffer, "on %s on %s", (LPSTR)gszDevice, (LPSTR)gszOutput);
  688.       SetDlgItemText(hWnd, IDC_PRINTTEXT2, (LPSTR)szBuffer);
  689.       SetFocus(GetDlgItem(hWnd, IDCANCEL));
  690.    }
  691.       return TRUE;     // Return TRUE because we called SetFocus()
  692.  
  693.    case WM_COMMAND:
  694.       bAbort = TRUE;
  695.       DestroyWindow(hWnd);
  696.       return TRUE;
  697.       break;
  698.       }
  699.    return FALSE;
  700. }
  701.